home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / Linux / scsi_linux.cpp
Encoding:
C/C++ Source or Header  |  2001-02-02  |  6.2 KB  |  262 lines

  1. /*
  2.  *  scsi_linux.cpp - SCSI Manager, Linux specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include "sysdeps.h"
  22.  
  23. #include <sys/ioctl.h>
  24. #include <linux/param.h>
  25. #include <linux/../scsi/sg.h>    // workaround for broken RedHat 6.0 /usr/include/scsi
  26. #include <unistd.h>
  27. #include <errno.h>
  28.  
  29. #include "main.h"
  30. #include "prefs.h"
  31. #include "user_strings.h"
  32. #include "scsi.h"
  33.  
  34. #define DEBUG 0
  35. #include "debug.h"
  36.  
  37.  
  38. // Global variables
  39. static int fds[8];                // fd's for 8 units
  40. static int fd;                    // Active fd (selected target)
  41.  
  42. static uint32 buffer_size;        // Size of data buffer
  43. static uint8 *buffer = NULL;    // Pointer to data buffer
  44.  
  45. static uint8 the_cmd[12];        // Active SCSI command
  46. static int the_cmd_len;
  47.  
  48.  
  49. /*
  50.  *  Initialization
  51.  */
  52.  
  53. void SCSIInit(void)
  54. {
  55.     int id;
  56.  
  57.     // Allocate buffer
  58.     buffer = (uint8 *)malloc(buffer_size = 0x10000);
  59.  
  60.     // Open generic SCSI driver for all 8 units
  61.     for (id=0; id<8; id++) {
  62.         char prefs_name[16];
  63.         sprintf(prefs_name, "scsi%d", id);
  64.         const char *str = PrefsFindString(prefs_name);
  65.         if (str) {
  66.             int fd = fds[id] = open(str, O_RDWR);
  67.             if (fd > 0) {
  68.                 // Is it really a Generic SCSI device?
  69.                 int timeout = ioctl(fd, SG_GET_TIMEOUT);
  70.                 if (timeout < 0) {
  71.                     // Error with SG_GET_TIMEOUT, doesn't seem to be a Generic SCSI device
  72.                     char msg[256];
  73.                     sprintf(msg, GetString(STR_SCSI_DEVICE_NOT_SCSI_WARN), str);
  74.                     WarningAlert(msg);
  75.                     close(fd);
  76.                     fds[id] = -1;
  77.                 } else {
  78.                     // Flush unwanted garbage from previous use of device
  79.                     uint8 reply[256];
  80.                     int old_fl = fcntl(fd, F_GETFL);
  81.                     fcntl(fd, F_SETFL, old_fl | O_NONBLOCK);
  82.                     while (read(fd, reply, sizeof(reply)) != -1 || errno != EAGAIN) ;
  83.                     fcntl(fd, F_SETFL, old_fl);
  84.                 }
  85.             } else {
  86.                 char msg[256];
  87.                 sprintf(msg, GetString(STR_SCSI_DEVICE_OPEN_WARN), str, strerror(errno));
  88.                 WarningAlert(msg);
  89.             }
  90.         }
  91.     }
  92.  
  93.     // Reset SCSI bus
  94.     SCSIReset();
  95. }
  96.  
  97.  
  98. /*
  99.  *  Deinitialization
  100.  */
  101.  
  102. void SCSIExit(void)
  103. {
  104.     // Close all devices
  105.     for (int i=0; i<8; i++) {
  106.         int fd = fds[i];
  107.         if (fd > 0)
  108.             close(fd);
  109.     }
  110.  
  111.     // Free buffer
  112.     if (buffer) {
  113.         free(buffer);
  114.         buffer = NULL;
  115.     }
  116. }
  117.  
  118.  
  119. /*
  120.  *  Check if requested data size fits into buffer, allocate new buffer if needed
  121.  */
  122.  
  123. static bool try_buffer(uint32 size)
  124. {
  125.     size += sizeof(struct sg_header) + 12;
  126.     if (size <= buffer_size)
  127.         return true;
  128.  
  129.     uint8 *new_buffer = (uint8 *)malloc(size);
  130.     if (new_buffer == NULL)
  131.         return false;
  132.     free(buffer);
  133.     buffer = new_buffer;
  134.     buffer_size = size;
  135.     return true;
  136. }
  137.  
  138.  
  139. /*
  140.  *  Set SCSI command to be sent by scsi_send_cmd()
  141.  */
  142.  
  143. void scsi_set_cmd(int cmd_length, uint8 *cmd)
  144. {
  145.     memcpy(the_cmd, cmd, the_cmd_len = cmd_length);
  146. }
  147.  
  148.  
  149. /*
  150.  *  Check for presence of SCSI target
  151.  */
  152.  
  153. bool scsi_is_target_present(int id)
  154. {
  155.     return fds[id] > 0;
  156. }
  157.  
  158.  
  159. /*
  160.  *  Set SCSI target (returns false on error)
  161.  */
  162.  
  163. bool scsi_set_target(int id, int lun)
  164. {
  165.     int new_fd = fds[id];
  166.     if (new_fd < 0)
  167.         return false;
  168.     if (new_fd != fd) {
  169.         // Clear autosense data
  170.         struct sg_header *h = (struct sg_header *)buffer;
  171.         h->sense_buffer[2] = 0;
  172.     }
  173.     fd = new_fd;
  174.     return true;
  175. }
  176.  
  177.  
  178. /*
  179.  *  Send SCSI command to active target (scsi_set_command() must have been called),
  180.  *  read/write data according to S/G table (returns false on error); timeout is in 1/60 sec
  181.  */
  182.  
  183. bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
  184. {
  185.     static int pack_id = 0;
  186.  
  187.     // Check if buffer is large enough, allocate new buffer if needed
  188.     if (!try_buffer(data_length)) {
  189.         char str[256];
  190.         sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
  191.         ErrorAlert(str);
  192.         return false;
  193.     }
  194.  
  195.     // Process S/G table when writing
  196.     if (!reading) {
  197.         D(bug(" writing to buffer\n"));
  198.         uint8 *buffer_ptr = buffer + sizeof(struct sg_header) + the_cmd_len;
  199.         for (int i=0; i<sg_size; i++) {
  200.             uint32 len = sg_len[i];
  201.             D(bug("  %d bytes from %08lx\n", len, sg_ptr[i]));
  202.             memcpy(buffer_ptr, sg_ptr[i], len);
  203.             buffer_ptr += len;
  204.         }
  205.     }
  206.  
  207.     // Request Sense and autosense data valid?
  208.     struct sg_header *h = (struct sg_header *)buffer;
  209.     int res;
  210.     if (the_cmd[0] == 0x03 && (h->sense_buffer[2] & 0x0f)) {
  211.  
  212.         // Yes, fake command
  213.         D(bug(" autosense\n"));
  214.         memcpy(buffer + sizeof(struct sg_header), h->sense_buffer, 16);
  215.         res = 0;
  216.         *stat = 0;
  217.  
  218.     } else {
  219.  
  220.         // No, send regular command
  221.         int to = timeout * HZ / 60;
  222.         ioctl(fd, SG_SET_TIMEOUT, &to);
  223.         D(bug(" sending command, length %d\n", data_length));
  224.         int request_size, reply_size;
  225.         if (reading) {
  226.             h->pack_len = request_size = sizeof(struct sg_header) + the_cmd_len;
  227.             h->reply_len = reply_size = sizeof(struct sg_header) + data_length;
  228.         } else {
  229.             h->pack_len = request_size = sizeof(struct sg_header) + the_cmd_len + data_length;
  230.             h->reply_len = reply_size = sizeof(struct sg_header);
  231.         }
  232.         h->pack_id = pack_id++;
  233.         h->result = 0;
  234.         h->twelve_byte = (the_cmd_len == 12);
  235.         h->sense_buffer[2] = 0;
  236.         memcpy(buffer + sizeof(struct sg_header), the_cmd, the_cmd_len);
  237.         res = write(fd, buffer, request_size);
  238.         D(bug(" request sent, actual %d, result %d\n", res, h->result));
  239.         if (res >= 0) {
  240.             res = read(fd, buffer, reply_size);
  241.             D(bug(" reply read, actual %d, result %d\n", res, h->result));
  242.         }
  243.         if (h->sense_buffer[2] & 0x0f)
  244.             *stat = 2;    // Check condition
  245.         else
  246.             *stat = 0;    // No error
  247.     }
  248.  
  249.     // Process S/G table when reading
  250.     if (reading && h->result == 0) {
  251.         D(bug(" reading from buffer\n"));
  252.         uint8 *buffer_ptr = buffer + sizeof(struct sg_header);
  253.         for (int i=0; i<sg_size; i++) {
  254.             uint32 len = sg_len[i];
  255.             D(bug("  %d bytes to %08lx\n", len, sg_ptr[i]));
  256.             memcpy(sg_ptr[i], buffer_ptr, len);
  257.             buffer_ptr += len;
  258.         }
  259.     }
  260.     return res >= 0;
  261. }
  262.